package com.linc.ds;

public class MyLinkedList<E> {
  protected static class Node<E> {
    public E data;
    public Node<E> next;

    public Node(E data) {
      this.data = data;
      this.next = null;
    }
  }

  private Node<E> head;
  private int len;

  protected static <E> void setNext(Node<E> first, Node<E> second) {
    first.next = second;
  }

  protected void setHead(Node<E> head) {
    this.head = head;
  }

  protected Node<E> getHead() {
    return head;
  }

  public MyLinkedList() {
    head = null;
    len = 0;
  }

  public void insertAtHead(E e) {
    insertAtPos(e, 0);
  }

  public void insertAtTail(E e) {
    insertAtPos(e, len);
  }

  public Boolean insertAtPos(E e, int pos) {
    if (pos < 0 || pos > len) {
      return false;
    }

    // 在pos位置插入
    var cu = head;
    for (int i = 0; i < pos - 1; i++) {
      cu = cu.next;
    }
    var newNode = new Node<>(e);
    if (pos == 0) {
      newNode.next = head;
      head = newNode;
    } else {
      newNode.next = cu.next;
      cu.next = newNode;
    }
    len++;
    return true;
  }

  public E delete(int pos) {
    if (pos < 0 || pos >= len) {
      return null;
    }

    if (pos == 0) {
      var r = head.data;
      head = head.next;
      len--;
      return r;
    }

    var cu = head;
    for (int i = 0; i < pos - 1; i++) {
      cu = cu.next;
    }
    var r = cu.next.data;
    cu.next = cu.next.next;
    len--;
    return r;
  }

  protected int getLen() {
    return len;
  }

  protected void setLen(int len) {
    this.len = len;
  }

  protected E getData(int pos) {

    var node = getNode(pos);

    return node == null ? null : node.data;
  }

  @Override
  public String toString() {
    var temp = head;
    var builder = new StringBuilder();
    builder.append(this.getClass().getSimpleName()).append(": ");
    if (temp != null) {
      for (int i = 1; i < len; i++) {
        builder.append(temp.data).append(" -> ");
        temp = temp.next;
      }
      builder.append(temp.data);
    }

    return builder.toString();
  }

  protected void incLen() {
    len++;
  }

  protected void decLen() {
    len--;
  }

  protected Boolean isEmpty() {
    return len == 0;
  }

  protected Node<E> getNode(int pos) {
    if (pos < 0 || pos >= len) return null;
    var r = head;
    for (int i = 0; i < pos; i++) {
      r = r.next;
    }
    return r;
  }
}
